#include "gameconsole.h"
#include <assert.h>
using namespace spacedefender;

GameConsole GameConsole::_gameConsole;

GameConsole* GameConsole::GetInstance()
{
	return &_gameConsole;
}

GameConsole::GameConsole() : CONSOLE_LINE_LENGTH(85) , CONSOLE_LINE_COUNT(15)
{
	_visible = false;
	_root = 0;
	_sceneMgr = 0;
	_rect = 0;
	_textbox = 0;
	_overlay = 0;
	_start_line = 0;
	_update_overlay = false;
}

GameConsole::~GameConsole()
{
	
}

void GameConsole::Shutdown()
{
	
	if(_rect)
	{
		delete _rect;
		_rect = 0;
	}
	
	if(_sceneNode)
	{
		_sceneMgr->destroySceneNode(_sceneNode);
		_sceneNode = 0;
	}
	
	if(_root)
	{
        Ogre::OverlayManager::getSingleton().destroy( _overlay );
        _textbox = 0;
        _overlay = 0;
	}
	
	_sceneMgr = 0;
	_root = 0;
	
}

void GameConsole::SetVisible(const bool visible)
{
	_visible = visible;
}

const bool GameConsole::IsVisible() const
{
	return _visible;
}

void GameConsole::Init(Ogre::Root* root)
{
	assert(root->getSceneManagerIterator().hasMoreElements());
	
	_root = root;
	_sceneMgr = _root->getSceneManagerIterator().getNext();
	
	_height = 1;
	_rect = new Ogre::Rectangle2D(true);
	_rect->setCorners(-1, 1, 1, 1 - _height);
	_rect->setMaterial("console/background");
	_rect->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY);
	_rect->setBoundingBox(Ogre::AxisAlignedBox(-100000.0 * Ogre::Vector3::UNIT_SCALE, 100000.0 * Ogre::Vector3::UNIT_SCALE));
	_sceneNode = _sceneMgr->getRootSceneNode()->createChildSceneNode("#GameConsole");
	_sceneNode->attachObject(_rect);
	
	_textbox = Ogre::OverlayManager::getSingleton().createOverlayElement("TextArea","ConsoleText");
	_textbox->setCaption("? ");
	_textbox->setMetricsMode(Ogre::GMM_RELATIVE);
	_textbox->setPosition(0,0);
	_textbox->setParameter("font_name","StarWars");
	_textbox->setParameter("colour_top","1 1 1");
	_textbox->setParameter("colour_bottom","1 1 1");
	_textbox->setParameter("char_height","0.03");

	_overlay = Ogre::OverlayManager::getSingleton().create("Console");   
	_overlay->add2D((Ogre::OverlayContainer*)_textbox);
	_overlay->show();
}


bool GameConsole::update(const Ogre::FrameEvent& evt)
{
	if(_visible && _height < 1){
		_height += evt.timeSinceLastFrame*2;
		_textbox->show();
		if(_height >= 1){
			_height = 1;
		}
	}
	else if(!_visible && _height > 0){
		_height -= evt.timeSinceLastFrame * 2;
		if(_height <= 0){
			_height = 0;
			_textbox->hide();
		}
	}

	_textbox->setPosition(0,(_height - 1) * 0.5);
	_rect->setCorners(-1,1 + _height,1,1 - _height);

	if(_update_overlay){
		Ogre::String text;
		std::list<Ogre::String>::iterator i,start,end;

		//make sure is in range
		if(_start_line > _lines.size())
			_start_line = _lines.size();

		int lcount=0;
		start = _lines.begin();
		for(int c = 0; c < _start_line;c++)
			start++;
		end = start;
		for(int c = 0; c < CONSOLE_LINE_COUNT;c++){
			if(end == _lines.end())
				break;
			end++;
		}
		for(i = start; i != end; i++)
			text += (*i) + "\n";

		//add the prompt
		text += "? " + _prompt;

		_textbox->setCaption(text);
		_update_overlay = false;
	}
	
	return true;
}

void GameConsole::onKeyPressed(const OIS::KeyEvent &arg)
{
	if(!_visible)
		return;

	if (arg.key == OIS::KC_RETURN)
	{
		//split the parameter list
		const char *str = _prompt.c_str();
		std::vector<Ogre::String> params;
		Ogre::String param="";
		for(int c=0; c < _prompt.length();c++){
			if(str[c] == ' '){
				if(param.length())
				   params.push_back(param);
				param = "";
			}
			else
				param+=str[c];
		}
		if(param.length())
			params.push_back(param);

		//try to execute the command
		std::map<Ogre::String, void(*)(std::vector<Ogre::String>&)>::iterator i;
		
		for(i = _commands.begin(); i != _commands.end();i++){
			if((*i).first==params[0]){
				if((*i).second)
					(*i).second(params);
				break;
			}
		}

		print(_prompt);
		_prompt = "";
	}
	if (arg.key == OIS::KC_BACK)
		_prompt = _prompt.substr(0,_prompt.length()-1);
	if (arg.key == OIS::KC_PGUP)
	{
		if(_start_line > 0)
			_start_line--;
	}
	if (arg.key == OIS::KC_PGDOWN)
	{
		if(_start_line < _lines.size())
			_start_line++;
	}
	else
	{
		char legalchars[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890+!\"#%&/()=?[]\\*-_.:,; ";
		for(int c=0; c < sizeof(legalchars);c++){
			if(legalchars[c] == arg.text){
				_prompt += arg.text;
				break;
			}
		}
	}
	_update_overlay=true;
}

void GameConsole::print(const Ogre::String &text)
{
	//subdivide it into lines
	const char *str=text.c_str();
	int start=0,count=0;
	int len=text.length();
	Ogre::String line;
	for(int c = 0; c < len; c++){
		if(str[c] == '\n' || line.length() >= CONSOLE_LINE_LENGTH){
			_lines.push_back(line);
			line="";
		}
		if(str[c]!='\n')
			line+=str[c];
	}
	if(line.length())
		_lines.push_back(line);
	if(_lines.size() > CONSOLE_LINE_COUNT)
		_start_line = _lines.size() - CONSOLE_LINE_COUNT;
	else
		_start_line=0;
	_update_overlay=true;
}

void GameConsole::AddCommand(const Ogre::String &command, void (*func)(std::vector<Ogre::String>&))
{
   _commands[command] = func;
}

void GameConsole::RemoveCommand(const Ogre::String &command)
{
   _commands.erase(_commands.find(command));
}

void GameConsole::ClearConsole()
{
	_lines.clear();
}